///////////////////////////////////////////////////////////////////////////////////////////////////
/// \file formic/fqmc/orb_opt_acc.h
///
/// \brief   header file for an accumulator to compute energy derivatives w.r.t. the integrals
///
///////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef FORMIC_FQMC_ORB_OPT_ACC_HEADER
#define FORMIC_FQMC_ORB_OPT_ACC_HEADER

#include<boost/shared_ptr.hpp>

#include<formic/fqmc/accumulator.h>
#include<formic/wfn/coeff_obj.h>
#include<formic/vector/vector.h>

namespace formic {

  class InputBase;
  class Configuration;

  namespace fqmc {

    ///////////////////////////////////////////////////////////////////////////////////////////////////
    /// \brief  accumulator for energy derivatives w.r.t. the integrals
    ///
    ///////////////////////////////////////////////////////////////////////////////////////////////////
    template<class S> class OrbOptAcc : public formic::Accumulator<S> {

      private:

        /// \brief  the number of orbitals in the basis
        int _norb;

        /// \brief  energy derivatives w.r.t. the one electron integrals
        formic::Matrix<S,int> _oei_der;

        /// \brief  energy derivatives w.r.t. the two electron integrals (dense storage)
        formic::Vector<S,int> _tei_dns_der;

        /// \brief  energy derivatives w.r.t. the two electron integrals (compact storage)
        formic::Vector<S,int> _tei_cmp_der;

        /// \brief  orbital coefficient matrix
        formic::ConstMatrix<S,int> _oc;

//        /// \brief  average of the orbital coefficient matrix derivative ratios
//        formic::Matrix<S,int> _bare_oc_der_rat;
//
//        /// \brief  average of the local energy times the orbital coefficient matrix derivative ratios
//        formic::Matrix<S,int> _enrg_oc_der_rat;
//
//        /// \brief  matrix to hold the local orbital coefficient derivative ratios
//        formic::Matrix<S,int> _locl_oc_der_rat;

        /// \brief  the energy
        S _energy;

        /// \brief  sum of the squares of the value-to-guiding ratios
        double _vgs_total;

      public:

        /// \brief  return the accumulator's name
        std::string name() const { return "orbital optimization accumulator"; }

        OrbOptAcc(const int norb,
                  const formic::ConstMatrix<S,int> & oc,
                  const boost::shared_ptr<formic::CoeffObj<S> > & gf,
                  const boost::shared_ptr<formic::CoeffObj<S> > & vf);

        void child_accumulate(const formic::InputBase & userinp, const double w);

        void child_finalize(const formic::InputBase & userinp);

        void child_reset(const formic::Configuration & config);

        /// \brief  return a reference to the one electron integral derivative adjoints
        const formic::Matrix<S,int> & oei_der() const { return _oei_der; }

        /// \brief  return a reference to the compactly stored two electron integral derivative adjoints
        const formic::Vector<S,int> & tei_cmp_der() const { return _tei_cmp_der; }

    };

  } // end namespace fqmc

} // end namespace formic

#endif
